#define __GNU_SOURCE
#include "app_bt.h"
#include <string.h>
#include "log/log.h"
#include "app_serial.h"
#include "termios.h"
#include <unistd.h>

//蓝牙配置初始化
static int bt_init(Device *device){
    //0.串口初始化
    app_serial_init(device); //默认9600

    //1.设置串口非阻塞模式，方便测试
    app_serial_setBlock(device,0);
    tcflush(device->fd,TCIOFLUSH); //刷新
    //2.发送蓝牙初始化指令，测试蓝牙当前波特率9600（默认）
    //如果收到数据证明蓝牙串口也9600（115200收不到）需要提高到115200
    if(app_bt_status(device)==0){
        app_bt_setBraudRate(device,BT_BR_115200);
        //配置完重启蓝牙,并等待2秒
        app_bt_reset(device);
        sleep(2);
    }
    //4.测试结束并且配置完成可以串口提高波特率（初始化配置的9600）
    app_serial_setBraudRate(device,BR_115200);    
    //串口设置完刷新后才能生效
    int result= tcflush(device->fd,TCIOFLUSH); //刷新
    if(result!=0){
        log_error("串口波特率设置失败");
        return -1;
    }
    log_debug("串口波特率设置成功");
    //3.发送蓝牙配置指令
    app_bt_rename(device,"BaiLu");
    app_bt_setNetid(device,"8622");  //网络组ID相同
    app_bt_setMaddr(device,"0234");  //设备ID不同
    

    //5.设置串口阻塞模式（接收至少1字节数据）
    app_serial_setBlock(device,1);
    int result1= tcflush(device->fd,TCIOFLUSH); //刷新
    if(result1!=0){
        log_error("蓝牙初始化配置失败");
        return -1;
    }
    log_debug("蓝牙初始化配置成功");

    return 0;
}

//接收蓝牙应答ACK，确认是否发送成功（OK\r\n）
static int bt_ack(Device *device){
    //等待蓝牙回复 50ms
    usleep(50*1000);
    //读取串口中的蓝牙回应
    char ack[4];
    read(device->fd,ack,4);
    //判断是否是OK
    if(memcmp(ack,"OK\r\n",4)!=0){
        log_debug("蓝牙测试未通过");
        return -1;
    }
    return 0;
}

//初始化蓝牙(函数赋值到设备的属性)
//参数：设备 返回值：0成功，-1失败
int app_bt_init(Device *device){
    //设备属性传递函数指针
    device->pre_write=app_bt_preWrite;
    device->after_read=app_bt_afterRead;

    //初始化蓝牙配置
    bt_init(device);

    return 0;
}


//发送数据前格式转换（char数组-蓝牙数据）
//参数：数据容器，char数据长度 返回值:蓝牙数据长度
int app_bt_preWrite(char *data, int len){
    //1.判断char数组长度是否满足基本数据长度
    if(len<6){  //3+2+1
        log_error("数据长度不足，不满足解析要求\n");
        return -1;
    }

    //2.解析char数组数据
    //char格式：type(1) id_len(1) msg_len(1) id(2) msg(n)
    int conn_type=data[0];
    if(conn_type!=1){
        log_error("连接类型不是蓝牙\n");
        return -1;
    }
    int id_len=data[1];
    int msg_len=data[2];
    char id[id_len];
    memcpy(id,data+3,id_len);
    char msg[msg_len];
    memcpy(msg,data+3+id_len,msg_len);

    //3.拼接解析数据作为蓝牙数据发送（data作为容器容量要能装下）
    //蓝牙格式：AT+MESH \0 id msg \r\n
    memset(data,0,len);
    memcpy(data,"AT+MESH",8);   //AT+MESH \0
    memcpy(data+8,id,id_len);   //id
    memcpy(data+8+id_len,msg,msg_len);  //msg
    memcpy(data+8+id_len+msg_len,"\r\n",2);  //\r\n

    //4.返回蓝牙数据长度
    return 8+id_len+msg_len+2;
}


//定义全局变量，方便多个函数调用
static char read_buf[512];  //缓存蓝牙数据容器
static int buf_len=0;       //缓存蓝牙数据长度
static char blue_head[2]={0xf1,0xdd}; //蓝牙数据头 

static void delete_buf_data(int len){
    //把后面的数据移到前面，覆盖掉前面的数据(将参数2数组，复制到参数1数组，多长)
    memmove(read_buf,read_buf+len,buf_len-len);
    buf_len-=len;
}

//读取后格式转换（蓝牙数据-char数组）
//参数：数据容器，蓝牙数据长度 返回值:char数据长度
int app_bt_afterRead(char *data, int len){
    
    //1.将蓝牙数据存入缓存容器(追加到原本数据后,因为蓝牙数据是多次发送还有无效的)
    memcpy(read_buf+buf_len,data,len);
    buf_len+=len;
    //2.判断缓存数据是否满足有效数据长度
    //有效数据：f1 dd 07 23 23 ff ff 41 42 43 
    //头部(2)+后面剩余长度(1)+设备id(2)+接收方id(2)+msg(n)
    if(buf_len<8){
        //数据长度不够，继续接收
        return 0;
    }
    //3.处理数据为char数组
    //从data头开始找蓝牙有效数据头部，直到剩余不足8个字节（再小构不成有效数据）
    int i;
    for(i=0;i<buf_len-7;i++){
        //2.找头部信息(每次取俩字符比较，随着i增长比较完)
        if(memcmp(read_buf+i,blue_head,2)==0){
            //3.判断头部信息前面是否有数据，删除前面无用数据
            if(i>0){
                //删除前面i个数据，因为i=0指向第一个数据
                delete_buf_data(i);
                //如果删除无效数据后的缓冲数据长度只有2（头部），后面调用buf[2]会越界
                if(buf_len<8){
                    //数据长度不够，继续接收
                    return 0;
                }
            }
            //4.判断有效数据是否接收完整（msg可能很多字节，不止8）
            //总数据长度=后面数据长度（buf[2]）+头部（2）+数据长度（buf[2]占用的1字节）
            int data_len=read_buf[2]+3;
            //因为已经把无用数据删除，头部移动到buf的首字节，所以判断长度
            if(buf_len<data_len){
                log_debug("数据接收未完整，继续接收\n");
                return 0;
            }
            //5.接收完成，解析数据
            char id[2];
            memcpy(id,read_buf+3,2);
            //msg长度=剩余数据长(buf[2])-设备id(2)-接收方id(2)
            int msg_len=read_buf[2]-4;
            char msg[msg_len];  
            memcpy(msg,read_buf+7,msg_len);
            //6.拼接数据到data字符数组：conn_type id_len msg_len id msg
            memset(data,0,len);
            data[0]=1;
            data[1]=2;
            data[2]=msg_len;
            memcpy(data+3,id,2);
            memcpy(data+5,msg,msg_len);
            //7.数据可以返回，删除缓冲数据
            delete_buf_data(buf_len);
            return data_len;
        }
    }
    //8.如果i>0，并且前面for循环里拼接没返回，说明都是无效数据，删除
    //如果刚好最后一个数据是f1，因为for条件不删除后面7个且i=0不会删除
    if(i>0){
        //留下7个数据不会删除，因为删除是move，会把这7个数据移到buf开头，别的数据继续追加
        delete_buf_data(i);
    }
    return 0;
}

//判断蓝牙是否可用AT
int app_bt_status(Device *device){
    //向串口文件写入指令（就相当于串口发）
    write(device->fd,"AT\r\n",4);
    //有无回应ok消息，代表成功执行与否
    return bt_ack(device);
}

//蓝牙重命名AT+NAME(名称)
int app_bt_rename(Device *device,char *name){
    char cmd[32];
    sprintf(cmd,"AT+NAME%s\r\n",name);
    write(device->fd,cmd,strlen(cmd));
    return bt_ack(device);
}

//设置蓝牙波特率AT+BAUD(波特率枚举)
int app_bt_setBraudRate(Device *device, BTBaudRate baudRate){
    char cmd[32];
    //注意赋值时是字符
    sprintf(cmd,"AT+BAUD%c\r\n",baudRate); 
    write(device->fd,cmd,strlen(cmd));
    return bt_ack(device);
}

//重启蓝牙AT+RESET
int app_bt_reset(Device *device){
    write(device->fd,"AT+RESET\r\n",10);
    return bt_ack(device);
}

//设置蓝牙网络ID AT+NETID(网络ID:4位16进制字符串“0101”)
int app_bt_setNetid(Device *device, char *netid){
    char cmd[32];
    sprintf(cmd,"AT+NETID%s\r\n",netid);
    write(device->fd,cmd,strlen(cmd));
    return bt_ack(device);
}

//设置蓝牙MAC地址 AT+MADDR(MAC地址：4位16进制字符串“a1a2”)
int app_bt_setMaddr(Device *device, char *maddr){
    char cmd[32];
    sprintf(cmd,"AT+MADDR%s\r\n",maddr);
    write(device->fd,cmd,strlen(cmd));
    return bt_ack(device);
}

